package com.junchenrobot.mes.service.impl;

import com.fasterxml.jackson.databind.util.BeanUtil;
import com.github.rholder.retry.RetryException;
import com.junchenrobot.mes.client.KCClient;
import com.junchenrobot.mes.config.AsyncPool;
import com.junchenrobot.mes.core.AsyncPlcConnector;
import com.junchenrobot.mes.core.InputTaskHandler;
import com.junchenrobot.mes.core.TaskScheduled;
import com.junchenrobot.mes.dao.*;
import com.junchenrobot.mes.domain.*;
import com.junchenrobot.mes.enums.DeviceStatusEnum;
import com.junchenrobot.mes.enums.ExecuteStateEnum;
import com.junchenrobot.mes.enums.PoolStateEnum;
import com.junchenrobot.mes.exceptions.NotFoundException;
import com.junchenrobot.mes.exceptions.TaskNotFoundException;
import com.junchenrobot.mes.listener.source.WinderTaskRedisRepository;
import com.junchenrobot.mes.listener.source.WinderTaskRedisRepositoryImpl;
import com.junchenrobot.mes.response.BaseResponse;
import com.junchenrobot.mes.response.impl.MesResponse;
import com.junchenrobot.mes.response.impl.RcsResponse;
import com.junchenrobot.mes.service.ManualTaskService;
import com.junchenrobot.mes.vo.param.DeviceParam;
import com.junchenrobot.mes.vo.param.ManualTaskParam;
import com.junchenrobot.mes.vo.param.TaskIdParam;
import com.junchenrobot.mes.vo.param.WinderTimeParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.DatagramPacket;
import java.time.Instant;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ManualTaskServiceImpl implements ManualTaskService {

    private final WinderTaskDao winderTaskDao;

    private  final  WinderTimeDao winderTimeDao;

    private final DeviceDao deviceDao;

    private final WinderDao winderDao;

    private final AgvWorkDao agvWorkDao;

    private final KCClient kcClient;

    private final InputTaskHandler inputTaskHandler;

    private final TaskScheduled scheduled;

    private final AsyncPlcConnector plcConnector;
    private final WinderTaskRunDao winderTaskRunDao;

    @Autowired
    public ManualTaskServiceImpl(WinderTaskDao winderTaskDao, DeviceDao deviceDao, WinderDao winderDao,
                                 AgvWorkDao agvWorkDao, KCClient kcClient, InputTaskHandler inputTaskHandler,
                                 TaskScheduled scheduled, WinderTimeDao winderTimeDao,AsyncPlcConnector plcConnector, WinderTaskRunDao winderTaskRunDao) {
        this.winderTaskDao = winderTaskDao;
        this.winderTimeDao = winderTimeDao;
        this.deviceDao = deviceDao;
        this.winderDao = winderDao;
        this.agvWorkDao = agvWorkDao;
        this.kcClient = kcClient;
        this.inputTaskHandler = inputTaskHandler;
        this.scheduled = scheduled;
        this.plcConnector = plcConnector;
        this.winderTaskRunDao = winderTaskRunDao;
    }

    @Autowired
    WinderTaskRedisRepository winderTaskRedisRepository;

    /**
     * 手动添加任务
     *
     * @param manualTaskParam 人工任务参数
     * @return {@link BaseResponse}
     */
    @Override
    public BaseResponse manualAddTask(ManualTaskParam manualTaskParam) {
        Device device = deviceDao.getDevice(manualTaskParam.getDeviceName());
        Winder winder = winderDao.getWinder(manualTaskParam.getWinderId());
        // Winder winder = winderDao.getWinder(manualTaskParam.getWinderName());
        // // 查询agv作业
        AgvWork agvWork = agvWorkDao.getAgvWork(winder.getWinderLine(), winder.getWinderSpinningCode());
        boolean isNUll = Objects.isNull(agvWork);
        if (isNUll) {
            throw new NotFoundException("卷绕机任务未找到");
        }

        Integer direction = manualTaskParam.getDirection();
        String location = direction == 1 ? winder.getWinderLeftPosition() : winder.getWinderRightPosition();
        WinderTask build = WinderTask.builder()
                .taskCode(String.valueOf(Instant.now().toEpochMilli()))
                .taskDeviceId(device.getId())
                .taskDeviceName(device.getDeviceName())
                .taskType(manualTaskParam.getTaskType())
                .taskWinderLine(agvWork.getLine())
                .taskWinderId(agvWork.getId())
                .taskExecuteStatus(-1)
                .taskWinderLsh(agvWork.getLsh())
                .taskWinderSpinningCode(agvWork.getSpinNo())
                .taskLocation(location)
                .taskPoleCode(direction)
                .build();
        winderTaskDao.insertNewTask(build);
//        List<WinderTaskSpare> winderTaskSpareList = new LinkedList<>();
//        winderTaskSpareList.add(build);

//        winderTaskRedisRepository.save(list);
        inputTaskHandler.newTask(build);
        return new MesResponse<>().success();
    }


    /**
     * 手动删除任务
     *
     * @param taskIdParam 人工任务参数
     * @return
     */
    @Override
    public BaseResponse cancelTask(TaskIdParam taskIdParam) {
        WinderTask winderTask = winderTaskDao.getWinderTask(taskIdParam.getTaskId());
        Integer taskPoleCode = winderTask.getTaskPoleCode();

        if (Objects.isNull(winderTask)) {
            throw new TaskNotFoundException("任务未找到到");
        }
        String taskCode = winderTask.getTaskCode();
        if (AsyncPool.containsKey(taskCode)) {
            AsyncPool.cancel(taskCode);
        }

        if (winderTask.getTaskType() == 1) {//取料任务
            Integer offset = winderDao.selectOffset(winderTask.getTaskWinderLine(), winderTask.getTaskWinderSpinningCode());
            try {
                plcConnector.winderClear(offset);//清除改卷绕机DB块数据
            } catch (ExecutionException | RetryException e) {
                e.printStackTrace();
            }
        } else {//放料任务
            int offset = 0;
            if (taskPoleCode == 1) {//左杆
                offset = 2;
            }
            if (taskPoleCode == 2) {//右杆
                offset = 12;
            }
            try {
                plcConnector.transferClear(offset);//中转站清除取货请求以及产线机号流水号
            } catch (ExecutionException | RetryException e) {
                e.printStackTrace();
            }
        }
        // 删除任务
        //更改状态为执行完成
        winderTask.setTaskExecuteStatus(ExecuteStateEnum.TASK_FINISHED.getState());
        winderTask.setTaskRemark("取消任务");
        AsyncPool.cancel(taskCode);
        CompletableFuture.runAsync(() -> {
            agvWorkDao.updateWorkStatus(winderTask.getTaskWinderId(), 1);
            kcClient.deleteTask(taskCode);
            kcClient.resetDevice(winderTask.getTaskDeviceName());
        });
        //数据库中删除该任务
        winderTaskDao.deleteWinderTask(winderTask);
        WinderTaskRun winderTaskRun = WinderTaskRun.builder().build();
        BeanUtils.copyProperties(winderTask, winderTaskRun);
        //删除小车运行任务表任务
        winderTaskRunDao.deleteWinderTask(winderTaskRun);
        Integer taskType = winderTask.getTaskType();
        if (taskType == 1) {//取料
            deviceDao.updateDevicePoleStatus(winderTask.getTaskDeviceName(), winderTask.getTaskPoleCode(), PoolStateEnum.FEED_FAILURE.getState());
        } else {
            deviceDao.updateDevicePoleStatus(winderTask.getTaskDeviceName(), winderTask.getTaskPoleCode(), PoolStateEnum.COMPLETION_OF_TAKE_UP.getState());
        }
        return new MesResponse<>().success();
    }

    /**
     * 手动分派任务
     *
     * @return {@link BaseResponse}
     */
    @Override
    public BaseResponse dispatchTask() {
        // 取出一个任务
//        WinderTaskSpare winderTask = scheduled.takeTask();
//        if (Objects.nonNull(winderTask)) {
//
//       // 分配任务
//            scheduled.dispatchTask(winderTask);
//        }
        return new MesResponse<>().success();
    }
    /**
     * 修改停留时间
     * @return {@link BaseResponse}
     */
    @Override
    public BaseResponse updateWinderTime(WinderTimeParam winderTimeParam) {
            winderTimeDao.updateTaskByTaskCode(winderTimeParam.getId(), winderTimeParam.getBurstTime(),winderTimeParam.getVariety(),winderTimeParam.getModelNumber());
        return new MesResponse<>().success();
    }

    /**
     * 禁用avg小车状态
     *
     * @param deviceParam 小车名称状态
     * @return
     */
    @Override
    public BaseResponse updateDisableDevice(DeviceParam deviceParam) {
        Device device = deviceDao.getDevice(deviceParam.getDeviceName());
        List<WinderTask> winderTasks = winderTaskDao.listUnFinishedNameTask(deviceParam.getDeviceName());
        List<WinderTask> collect = winderTasks.stream()
                .filter(WinderTask -> WinderTask.getTaskPoleCode()==1)
                .collect(Collectors.toList());
        List<WinderTask> collect1 = winderTasks.stream()
                .filter(WinderTask -> WinderTask.getTaskPoleCode()==2)
                .collect(Collectors.toList());
        Integer deviceDisable = deviceParam.getDeviceDisable();
        switch (deviceDisable) {
            case 0:
                deviceDao.updateDevice(deviceParam.getDeviceName(), DeviceStatusEnum.PROHIBITED_TROLLEY.getIndex());
                break;
            case 1:
                if (device.getDeviceStatus() == 99 && collect.size()==0){
                    deviceDao.updateDevicePoleStatus(deviceParam.getDeviceName(), 1, PoolStateEnum.DISABLE_POOL.getState());
                }else{
                    return new MesResponse<>().fault( "小车在禁用状态下并且无任务才可以禁用杆子");
                }

                break;
            case 2 :
                if (device.getDeviceStatus() == 99 && collect1.size()==0){
                    deviceDao.updateDevicePoleStatus(deviceParam.getDeviceName(), 2, PoolStateEnum.DISABLE_POOL.getState());
                }else{
                    return new MesResponse<>().fault( "小车在禁用状态下并且无任务才可以禁用杆子");
                }

                break;
        }
        return new MesResponse<>().success();
    }

    /**
     * 启用avg小车状态
     *
     * @param deviceParam 小车名称状态
     * @return
     */
    @Override
    public BaseResponse updateEnableDevice(DeviceParam deviceParam) {
        Device device = deviceDao.getDevice(deviceParam.getDeviceName());
        Integer deviceDisable = deviceParam.getDeviceDisable();
        switch (deviceDisable) {
            case 0:
                //报错
                if (device.getDeviceStatus() != 99) {
                    return new MesResponse<>().fault( "小车在禁用状态下才可以启用");
                }
                //启用小车
                deviceDao.updateDevice(deviceParam.getDeviceName(), DeviceStatusEnum.IDLE.getIndex());
                break;
            case 1:
                //启用左杆
                if (device.getDeviceLeftPole() != 9){
                    return new MesResponse<>().fault( "左杆在禁用状态下才可以启用");
                }
                deviceDao.updateDevicePoleStatus(deviceParam.getDeviceName(), 1, PoolStateEnum.IDLE.getState());
                break;
            case 2:
                //启用右杆
                if (device.getDeviceRightPole() != 9){
                    return new MesResponse<>().fault( "右杆在禁用状态下才可以启用");
                }
                deviceDao.updateDevicePoleStatus(deviceParam.getDeviceName(), 2, PoolStateEnum.IDLE.getState());
                break;
        }
        return new MesResponse<>().success();
    }


}
